﻿// <copyright file="PrimitiveMeshBuilder.cs" company="Axelerate Solutions S.A.">
// Copyright (c) Axelerate Solutions S.A.  All rights reserved.
// </copyright>
namespace Axelerate.Silverlight3D.Media.Media3D
{
    using System;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Ink;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;

    /// <summary>
    /// File name: PrimitiveMeshBuilder.cs
    /// Company: Axelerate Solutions S.A.
    /// Created By: Daniel Rojas
    /// Created Date: 27/10/2008 04:57:30 h.
    /// Description: Utility class that generate primitive 3D Geometries. All the generated geometries ar expressed on a Mesh3DGeometry center on the 0,0,0 position.
    ///   <Modifications>
    ///   </Modifications>
    /// </summary>
    public class PrimitiveMeshBuilder
    {
        /// <summary>
        /// Create a MeshGeometry3D that represent a 3D Box based on the boxDef posision and size
        /// </summary>
        /// <param name="boxDef">Rect3D with the first vertex and the size on X,Y,Z for the box</param>
        /// <returns>MeshGeometry3D with the geometrical information of the 3D Box</returns>
        /// <remarks>the 0,0,0 position correspond to the center of the viewport and Y is positive to the top, X is positive to the right and Z is positive toward the front. This can change according to the point of view of the camera</remarks>
        public static MeshGeometry3D CreateBox(Rect3D boxDef)
        {
            MeshGeometry3D geometry = new MeshGeometry3D();
            Point3DCollection points = new Point3DCollection();
            points.Add(new Point3D(boxDef.X, boxDef.Y, boxDef.Z)); // 0
            points.Add(new Point3D(boxDef.X + boxDef.SizeX, boxDef.Y, boxDef.Z)); // 1
            points.Add(new Point3D(boxDef.X, boxDef.Y + boxDef.SizeY, boxDef.Z)); // 2
            points.Add(new Point3D(boxDef.X + boxDef.SizeX, boxDef.Y + boxDef.SizeY, boxDef.Z)); // 3

            points.Add(new Point3D(boxDef.X, boxDef.Y, boxDef.Z + boxDef.SizeZ)); // 4
            points.Add(new Point3D(boxDef.X + boxDef.SizeX, boxDef.Y, boxDef.Z + boxDef.SizeZ)); // 5 
            points.Add(new Point3D(boxDef.X, boxDef.Y + boxDef.SizeY, boxDef.Z + boxDef.SizeZ)); // 6
            points.Add(new Point3D(boxDef.X + boxDef.SizeX, boxDef.Y + boxDef.SizeY, boxDef.Z + boxDef.SizeZ)); // 7

            Int32Collection entityIndices = null;
            entityIndices = Int32Collection.Parse("1,0,2, 2,3,1, 4,5,6, 5,7,6, 2,6,7, 7,3,2, 0,1,5, 5,4,0, 3,7,5, 5,1,3, 2,0,4, 4,6,2");
            
            geometry.Positions = points;
            geometry.TriangleIndices = entityIndices;

            // I don't need normals and texture coordinates for this basic geometry

            return geometry;
        }

        
        public static MeshGeometry3D CreateLine3D(Point3D from, Point3D to, double lineWidth, Vector3D upVector)
        {
            MeshGeometry3D geometry = new MeshGeometry3D();
            Point3DCollection points = new Point3DCollection();
            Int32Collection indices = null;

            double HalfSize = lineWidth / 2.0;
            Vector3D lineDirection = from - to;
            
            lineDirection.Normalize();

            if (lineDirection.LengthSquared <= 0)
            {
                throw new Exception("Invalid line lenght. Review the from and to points");
            }
            if (lineWidth <= 0)
            {
                throw new Exception("Invalid line width. Must be grather than 0");
            }
            if (upVector.LengthSquared <= 0)
            {
                throw new Exception("Invalid up direction");
            }
            upVector.Normalize();
            Vector3D rightVector = Vector3D.CrossProduct(lineDirection, upVector);
            rightVector.Normalize();
            if (rightVector.LengthSquared <= 0)
            {
                throw new Exception("Invalid up direcction for the provided points");
            }
            points.Add(from + (HalfSize * rightVector)); // 0
            points.Add(from - (HalfSize * rightVector)); // 1

            points.Add(to + (HalfSize * rightVector)); // 2
            points.Add(to - (HalfSize * rightVector)); // 3

            indices = Int32Collection.Parse("0,1,3, 3,2,0");

            geometry.Positions = points;
            geometry.TriangleIndices = indices;

            // I don't need normals and texture coordinates for this basic geometry

            return geometry;
        }

        public static void AddLine3DToMesh(MeshGeometry3D mesh, Point3D from, Point3D to, double lineWidth, Vector3D upVector)
        {
            if (mesh == null || mesh.Positions == null || mesh.TriangleIndices == null)
            {
                // not valid state of the mesh to add the line 3D
                return;
            }
            Point3DCollection points = mesh.Positions;
            Int32Collection indices = mesh.TriangleIndices;

            double HalfSize = lineWidth / 2.0;
            Vector3D lineDirection = from - to;

            lineDirection.Normalize();

            if (lineDirection.LengthSquared <= 0)
            {
                throw new Exception("Invalid line lenght. Review the from and to points");
            }
            if (lineWidth <= 0)
            {
                throw new Exception("Invalid line width. Must be grather than 0");
            }
            if (upVector.LengthSquared <= 0)
            {
                throw new Exception("Invalid up direction");
            }
            upVector.Normalize();
            Vector3D rightVector = Vector3D.CrossProduct(lineDirection, upVector);
            rightVector.Normalize();
            if (rightVector.LengthSquared <= 0)
            {
                throw new Exception("Invalid up direcction for the provided points");
            }

            int firstPointIndex = points.Count;

            points.Add(from + (HalfSize * rightVector)); // 0
            points.Add(from - (HalfSize * rightVector)); // 1

            points.Add(to + (HalfSize * rightVector)); // 2
            points.Add(to - (HalfSize * rightVector)); // 3

            // normal indice line indices = Int32Collection.Parse("0,1,3, 3,2,0");
            indices.Add(firstPointIndex + 0); // 0
            indices.Add(firstPointIndex + 1); // 1
            indices.Add(firstPointIndex + 3); // 1

            indices.Add(firstPointIndex + 3); // 3
            indices.Add(firstPointIndex + 2); // 2
            indices.Add(firstPointIndex + 0); // 0

        }
    }
}
